home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / untar.zip / UNTAR.C
C/C++ Source or Header  |  1992-08-16  |  8KB  |  342 lines

  1. #include <stdio.h>
  2. #include <io.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <dir.h>
  6.  
  7. const char ego[] = "UNTAR 1.0, "__DATE__ " by Ron Aaron";
  8. const char version[] = "1.00";
  9.  
  10. int redirected = 0;
  11.  
  12. union tarheader {
  13.    char  junk[512];
  14.    struct {
  15.       char  name [100];
  16.       char  mode [8];
  17.       char  uid [8];
  18.       char  gid [8];
  19.       char  size [12];
  20.       char  mtime[12];
  21.       char  chksum[8];
  22.       char  link;
  23.       char  linkname[100];
  24.    } header;
  25. } th;
  26.  
  27. long adjust(long x)
  28. {
  29.    if (x == 0)
  30.       return 0;
  31.  
  32.    x = x/512 + 1;
  33.    return x * 512;
  34. }
  35.    
  36. static char program_name [ MAXFILE ];
  37.  
  38. void syntax(void)
  39. {
  40.    fprintf(stderr, "\n%s %s: another fine RonWare product!", program_name, version);
  41.    fprintf(stderr, "\n");
  42.    fprintf(stderr, "\nSyntax: %s [-x] tarfile", program_name);
  43.    fprintf(stderr, "\n  (stdin may be redirected, then 'program_name' isn't needed)");
  44.    fprintf(stderr, "\nThis program works on UNIX 'tar' files.  Its default action is to list");
  45.    fprintf(stderr, "\nthe files contained in the archive.");
  46.    fprintf(stderr, "\n");
  47.    fprintf(stderr, "\nIf the '-x' switch is given, the files will be extracted.");
  48.    fprintf(stderr, "\n");
  49.    fprintf(stderr, "\nWhere this utility differs from MKS tar or other tar programs is that");
  50.    fprintf(stderr, "\nit knows about MS-DOS filename limitations and tells you what it's doing");
  51.    fprintf(stderr, "\nwith the file names.");
  52.    fprintf(stderr, "\n");
  53.    fprintf(stderr, "\nFor example, an entry in a tar file may have a name like:");
  54.    fprintf(stderr, "\n     examples.may.92/areallongname.c");
  55.    fprintf(stderr, "\n%s converts that to:", program_name);
  56.    fprintf(stderr, "\n     examples.92/areallon.c");
  57.    fprintf(stderr, "\nThis program also ignores the checksum info in the tar headers, so it may");
  58.    fprintf(stderr, "\nbe used to perform file recovery when normal tar program won't.");
  59.    exit(3);
  60. }
  61.  
  62. void process_section( char *start, char *end )
  63. {
  64.    char *x, *y;
  65.    int count;
  66.  
  67.    /* section is of the form:
  68.          dir/  or
  69.          dir   or
  70.    */
  71.    // lowercase it, for consistency
  72.    for (x = start; x < end; x++)
  73.       *x = tolower(*x);
  74.  
  75.    // get rid of sections like a.b.c
  76.    for (x=start, count = 0; x<end; x++)
  77.    {
  78.       if (*x == '.')
  79.          ++count;
  80.  
  81.       if (count > 1)
  82.       {
  83.          // got a weird one, let's adjust it
  84.          y = end;
  85.          while (*y != '.')
  86.             --y;
  87.          x = strchr(start,'.');
  88.          strcpy(x,y);   // from last period to first period
  89.          end -= (y-x);
  90.          break;
  91.       }
  92.    }
  93.  
  94.    // get rid of sections which are too long
  95.    y = strchr(start, '.');
  96.    if (!y)
  97.    {
  98.       // no extension...
  99.       if ((end-start) > 8) // name > 8 chars
  100.          strcpy(start+8, end);
  101.    }
  102.    else if (y<end)
  103.    {
  104.       if ((y-start) > 8)
  105.       {
  106.          strcpy(start + 8, y);
  107.          end -= (y-start)-8;
  108.       }
  109.  
  110.       y = strchr(start, '.');
  111.       if ((end-y)>4)
  112.       {
  113.    //      strcpy(y+4, end);
  114.          strcpy(y+1, end-3);  // move last 3 chars
  115.       }
  116.    }
  117. }
  118.  
  119. char *legalname(char * oldname)
  120. {
  121.    char workbuf[100];
  122.    char *p = workbuf;
  123.    char *q;
  124.    int x;
  125.  
  126.    // make copy of buffer
  127.    strncpy(workbuf, oldname, 100);
  128.  
  129.    // convert illegal characters
  130.    while (p < (workbuf+100))
  131.    {
  132.       if (*p == ' ')
  133.       {
  134.          *p = '\0';
  135.          break;
  136.       }
  137.  
  138.       switch (*p) {
  139.          case ':':
  140.          case '*':
  141.          case '?':
  142.          case '^':
  143.          case '=':
  144.          case '+':
  145.          case '|':
  146.          case '<':
  147.          case '>':
  148.          case ',':
  149.             *p = '_';
  150.             break;
  151.          case '\\':
  152.             *p = '/';
  153.             break;
  154.       }
  155.       ++p;
  156.    }
  157.  
  158.    /* convert names of form:
  159.          a.b.c
  160.       to form:
  161.          a.c
  162.    */
  163.    p = q = workbuf;
  164.  
  165.    while (*p)
  166.    {
  167.       // find next section to process
  168.       q = strchr(p, '/');
  169.       if (q == NULL)
  170.          q = p + strlen(p);
  171.       if (p == q)
  172.       {
  173.          ++p;
  174.          continue;
  175.       }
  176.  
  177.       process_section(p,q);
  178.       q = strchr(p, '/');
  179.       if (q == NULL)
  180.          q = p + strlen(p);
  181.  
  182.       // bump p
  183.       p = (*q) ? q+1 : q;
  184.    }
  185.  
  186.    return workbuf;
  187. }
  188.  
  189. void spin()
  190. {
  191.    fprintf(stderr, "+");
  192. }
  193.  
  194. void makedir(char *name)
  195. {
  196.    // create the directory 'name'
  197.    if (name[strlen(name)-1] == '/')
  198.       name[strlen(name)-1] = '\0';
  199.  
  200.    if (mkdir(name) == -1)
  201.       perror(name);
  202. }
  203.  
  204. void unarcfile(FILE *tar, char *name, long size)
  205. {
  206.    long here;
  207.    FILE *out;
  208. #define BUF 8*1024
  209.    static char buf[BUF];
  210.    int cnt;
  211.  
  212.    here = ftell(tar);
  213.  
  214.    out = fopen(name, "wb");
  215.    if (out == NULL)
  216.    {
  217.       // is the problem that there's a path prepended which we don't have?
  218.       fnsplit(name, NULL, buf, NULL, NULL);
  219.       makedir(buf);
  220.       out = fopen(name, "wb");
  221.       if (out == NULL)
  222.       {
  223.          sprintf(buf,"cannot create file [%s]", name);
  224.          perror(buf);
  225.       }
  226.    }
  227.    else
  228.    {
  229.       while (size)
  230.       {
  231.          spin();
  232.          fread(buf, BUF, 1, tar);
  233.          if (cnt == -1)
  234.          {
  235.             sprintf(buf, "error in read from [%s]", name);
  236.             perror(buf);
  237.             break;
  238.          }
  239.          cnt = (BUF > size) ? size : BUF;
  240.          fwrite(buf, 1, cnt, out);
  241. //         fputc(fgetc(tar), out);
  242.          size -= cnt;
  243.       }
  244.       fclose(out);
  245.    }
  246.  
  247.    fseek(tar, here, SEEK_SET);
  248. }
  249.  
  250. void progname( char *name, char *oname)
  251. {
  252.    fnsplit(oname, NULL, NULL, name, NULL);
  253. }
  254.  
  255. void main( int argc, char **argv)
  256. {
  257.       FILE *tar;
  258.       long size, origin;
  259.       int x;
  260.       int extract = 0;
  261.       char name[100];
  262.  
  263.       progname(program_name , argv[0]);
  264.  
  265.       redirected = !isatty(fileno(stdout));
  266.  
  267.       if ((isatty(fileno(stdin))) && (argc != 2) && (argc != 3))
  268.          syntax();
  269.       else
  270.       {
  271.          if (argv[1][0] == '-')
  272.          {
  273.             if (argv[1][1] == 'x') ++extract;
  274.             else syntax();
  275.          }
  276.  
  277.          if (argc > 3) syntax;
  278.  
  279.          // open file if stdin not redirected, else use stdin
  280.          if (isatty(fileno(stdin)))
  281.             tar = fopen(argv[--argc], "rb");
  282.          else
  283.             tar = stdin;
  284.  
  285.          if (tar == NULL)
  286.             fprintf(stderr, "\nCannot open file %s", argv[argc]);
  287.          else
  288.          {
  289.             while (!feof(tar))
  290.             {
  291.                fread(&th, 1, sizeof(th), tar);
  292.                origin = ftell(tar);
  293.  
  294.                if (th.header.name[0] == 0 || th.header.name[0] == ' ')
  295.                   break;
  296.  
  297.                printf("\n%s: %s, ",
  298.                   (th.header.link == '5') ? "Dir " : "File",
  299.                   th.header.name
  300.                   );
  301.                if (redirected)
  302.                   fprintf(stderr, "\n%s: %s, ",
  303.                      (th.header.link == '5') ? "Dir " : "File",
  304.                      th.header.name);
  305.  
  306.                size = 0;
  307.                for (x=0; x<12; x++)
  308.                {
  309.                   if (th.header.size[x] != ' ' && th.header.size[x] != '\0')
  310.                   {
  311.                      size *= 8;
  312.                      size += th.header.size[x] - '0';
  313.                   }
  314.                }
  315.                printf(" (%ld)", size);
  316.                strcpy(name, legalname(th.header.name));
  317.                printf(" [%s]", name);
  318.  
  319.                if (redirected)
  320.                {
  321.                   fprintf(stderr," (%ld)", size);
  322.                   strcpy(name, legalname(th.header.name));
  323.                   fprintf(stderr, " [%s]", name);
  324.                }
  325.  
  326.                if (extract)
  327.                {
  328.                   if (th.header.link == '5') // directory
  329.                      makedir(name);
  330.                   else
  331.                      unarcfile(tar, name, size);
  332.                }
  333.  
  334.                fseek(tar, adjust(size) + origin, SEEK_SET);
  335.             }
  336.  
  337.             if (isatty(fileno(stdin)))
  338.                fclose(tar);
  339.          }
  340.       }
  341. }
  342.